package q1.project.modules.system.role.service;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import q1.project.common.context.TenantContext;
import q1.project.common.enums.EnableStatusEnum;
import q1.project.core.exception.BusinessException;
import q1.project.core.jpa.WhereBuilderNow;
import q1.project.modules.system.role.dao.PermissionDao;
import q1.project.modules.system.role.dao.RoleDao;
import q1.project.modules.system.role.entity.MenuEntity;
import q1.project.modules.system.role.entity.PermissionEntity;
import q1.project.modules.system.role.entity.RoleEntity;
import q1.project.modules.system.role.model.MenuVm;
import q1.project.modules.system.role.model.PermissionVm;
import q1.project.modules.system.role.model.RoleVm;

/**
 * 角色服务实现
 *
 * @author Q1 Team
 * @version 1.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class RoleService {

  private final RoleDao roleDao;
  private final PermissionDao permissionDao;
  private final UserRoleService userRoleService;

  @Transactional(rollbackFor = Exception.class)
  public RoleVm.RoleResponse createRole(RoleEntity role) {
    log.info("创建角色: roleCode={}", role.getRoleCode());

    // 校验角色编码是否已存在
    if (roleDao.findByRoleCode(role.getRoleCode()).isPresent()) {
      log.warn("角色编码已存在: {}", role.getRoleCode());
      throw new BusinessException("角色编码已存在");
    }

    role = roleDao.save(role);
    log.info("角色创建成功: id={}, roleCode={}", role.getId(), role.getRoleCode());

    return convertToResponse(role);
  }

  @Transactional(rollbackFor = Exception.class)
  public RoleVm.RoleResponse updateRole(RoleEntity role) {
    log.info("更新角色: id={}", role.getId());

    RoleEntity existingRole =
        roleDao.findById(role.getId()).orElseThrow(() -> new BusinessException("角色不存在"));

    // 更新基本信息
    existingRole.setRoleName(role.getRoleName());
    existingRole.setDescription(role.getDescription());
    existingRole.setStatus(role.getStatus());

    existingRole = roleDao.save(existingRole);
    log.info("角色更新成功: id={}, roleCode={}", existingRole.getId(), existingRole.getRoleCode());

    return convertToResponse(existingRole);
  }

  @Transactional(rollbackFor = Exception.class)
  public void deleteRole(String id) {
    log.info("删除角色: id={}", id);

    RoleEntity role = roleDao.findById(id).orElseThrow(() -> new BusinessException("角色不存在"));

    roleDao.delete(role);

    log.info("角色删除成功: id={}, roleCode={}", id, role.getRoleCode());
  }

  public RoleVm.RoleResponse getRoleById(String id) {
    log.debug("查询角色: id={}", id);

    RoleEntity role = roleDao.findById(id).orElseThrow(() -> new BusinessException("角色不存在"));

    return convertToResponse(role);
  }

  public RoleVm.RoleResponse getRoleByCode(String roleCode) {
    log.debug("根据角色编码查询角色: roleCode={}", roleCode);

    RoleEntity role =
        roleDao.findByRoleCode(roleCode).orElseThrow(() -> new BusinessException("角色不存在"));

    return convertToResponse(role);
  }

  public Page<RoleVm.RoleResponse> listRoles(RoleVm.RoleQuery query) {
    log.debug(
        "分页查询角色: page={}, size={}, keyword={}, roleCode={}, roleName={}, status={}",
        query.getPage(),
        query.getSize(),
        query.getKeyword(),
        query.getRoleCode(),
        query.getRoleName(),
        query.getStatus());

    query.validate();
    String tenantId = TenantContext.getTenantId();

    // 如果查询参数中指定了租户ID，使用指定的租户ID；否则使用当前租户ID
    String queryTenantId =
        query.getTenantId() != null && !query.getTenantId().isEmpty()
            ? query.getTenantId()
            : tenantId;

    // 使用WhereBuilderNow构建动态查询条件
    WhereBuilderNow<RoleEntity> builder = new WhereBuilderNow<>();
    builder.init(query);

    Specification<RoleEntity> spec =
        builder.build(
            w -> {
              // 租户ID条件（必须）
              w.stringEqual("tenantId", queryTenantId);

              // 角色编码模糊查询
              if (StringUtils.hasText(query.getRoleCode())) {
                w.stringContain("roleCode", query.getRoleCode());
              }

              // 角色名称模糊查询
              if (StringUtils.hasText(query.getRoleName())) {
                w.stringContain("roleName", query.getRoleName());
              }

              // 状态精确查询
              if (StringUtils.hasText(query.getStatus())) {
                try {
                  EnableStatusEnum status = EnableStatusEnum.valueOf(query.getStatus());
                  w.enumEqual("status", status);
                } catch (IllegalArgumentException e) {
                  log.warn("无效的角色状态: {}", query.getStatus());
                }
              }

              // 关键词搜索（如果有关键词，在多个字段中搜索）
              if (StringUtils.hasText(query.getKeyword())) {
                w.keywordSearch(query.getKeyword(), "roleCode", "roleName", "description");
              }

              // 排序：按创建时间降序
              w.descOrder("createTime");
            });

    // 执行查询
    Page<RoleEntity> page = roleDao.findAll(spec, builder.getPageable());

    return page.map(this::convertToResponse);
  }

  public List<RoleVm.RoleResponse> listEnabledRoles() {
    log.debug("查询所有启用的角色");

    List<RoleEntity> roles = roleDao.findByStatus(EnableStatusEnum.ACTIVE);

    return roles.stream().map(this::convertToResponse).collect(Collectors.toList());
  }

  @Transactional(rollbackFor = Exception.class)
  public void assignPermissions(String roleId, Set<String> permissionIds) {
    log.info("分配角色权限: roleId={}, permissionIds={}", roleId, permissionIds);

    RoleEntity role = roleDao.findById(roleId).orElseThrow(() -> new BusinessException("角色不存在"));

    // 分配权限
    userRoleService.assignPermissionsToRole(roleId, permissionIds);

    log.info("角色权限分配成功: roleId={}, permissionCount={}", roleId, permissionIds.size());
  }

  /** 转换为VO对象 */
  private RoleVm.RoleResponse convertToResponse(RoleEntity entity) {
    return new RoleVm.RoleResponse(
        entity.getId(),
        entity.getRoleCode(),
        entity.getRoleName(),
        entity.getDescription(),
        entity.getStatus());
  }

  @Transactional(rollbackFor = Exception.class)
  public void assignMenus(String roleId, Set<String> menuIds) {
    log.info("分配角色菜单: roleId={}, menuIds={}", roleId, menuIds);

    RoleEntity role = roleDao.findById(roleId).orElseThrow(() -> new BusinessException("角色不存在"));

    // 分配菜单
    userRoleService.assignMenusToRole(roleId, menuIds);

    log.info("角色菜单分配成功: roleId={}, menuCount={}", roleId, menuIds.size());
  }

  /** 转换权限为VO对象 */
  private PermissionVm.PermissionResponse convertPermissionToResponse(PermissionEntity entity) {
    return new PermissionVm.PermissionResponse(
        entity.getId(),
        entity.getPermissionCode(),
        entity.getPermissionName(),
        entity.getDescription(),
        entity.getModule(),
        entity.getResource(),
        entity.getAction(),
        entity.getStatus());
  }

  /** 转换菜单为VO对象 */
  private MenuVm.MenuResponse convertMenuToResponse(MenuEntity entity) {
    MenuVm.MenuResponse response = new MenuVm.MenuResponse();
    response.setId(entity.getId());
    response.setParentId(entity.getParentId());
    response.setMenuCode(entity.getMenuCode());
    response.setMenuName(entity.getMenuName());
    response.setMenuType(entity.getMenuType());
    response.setPath(entity.getPath());
    response.setComponent(entity.getComponent());
    response.setIcon(entity.getIcon());
    response.setSortOrder(entity.getSortOrder());
    response.setRemark(entity.getRemark());
    response.setEnabled(entity.getStatus() == EnableStatusEnum.ACTIVE);
    return response;
  }
}
